#include "StdAfx.h"
#include "AnsiMemFile.h"

CAnsiMemFile::CAnsiMemFile(UINT nGrowBytes)
{
	ASSERT(nGrowBytes <= UINT_MAX);

	m_nGrowBytes = nGrowBytes;
	m_nPosition = 0;
	m_nBufferSize = 0;
	m_nFileSize = 0;
	m_lpBuffer = NULL;
	m_bAutoDelete = TRUE;

	//GrowFile( 1024 );

}

CAnsiMemFile::CAnsiMemFile(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes)
{
	if (lpBuffer == NULL && nBufferSize != 0) 
	{
//		AfxThrowInvalidArgException();
	}

	ASSERT(nGrowBytes <= UINT_MAX);

	m_nGrowBytes = nGrowBytes;
	m_nPosition = 0;
	m_nBufferSize = nBufferSize;
	m_nFileSize = nGrowBytes == 0 ? nBufferSize : 0;
	m_lpBuffer = lpBuffer;
	m_bAutoDelete = FALSE;
}

void CAnsiMemFile::Attach(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes) 
{
	if (lpBuffer == NULL && nBufferSize != 0) 
	{
//		AfxThrowInvalidArgException();
	}

	ASSERT(m_lpBuffer == NULL);

	m_nGrowBytes = nGrowBytes;
	m_nPosition = 0;
	m_nBufferSize = nBufferSize;
	m_nFileSize = nGrowBytes == 0 ? nBufferSize : 0;
	m_lpBuffer = lpBuffer;
	m_bAutoDelete = FALSE;
}

BYTE* CAnsiMemFile::Detach()
{
	BYTE* lpBuffer = m_lpBuffer;
	m_lpBuffer = NULL;
	m_nFileSize = 0;
	m_nBufferSize = 0;
	m_nPosition = 0;

	return lpBuffer;
}

CAnsiMemFile::~CAnsiMemFile()
{
	// Close should have already been called, but we check anyway
	if (m_lpBuffer)
		Close();
	ASSERT(m_lpBuffer == NULL);

	m_nGrowBytes = 0;
	m_nPosition = 0;
	m_nBufferSize = 0;
	m_nFileSize = 0;
}

BYTE* CAnsiMemFile::Alloc(SIZE_T nBytes)
{
	return (BYTE*)malloc(nBytes);
}

BYTE* CAnsiMemFile::Realloc(BYTE* lpMem, SIZE_T nBytes)
{
	ASSERT(nBytes > 0);	// nBytes == 0 means free		
	return (BYTE*)realloc(lpMem, nBytes);
}

#pragma intrinsic(memcpy)
BYTE* CAnsiMemFile::Memcpy(BYTE* lpMemTarget, const BYTE* lpMemSource,
					   SIZE_T nBytes)
{
	ASSERT(lpMemTarget != NULL);
	ASSERT(lpMemSource != NULL);

//	ASSERT(AfxIsValidAddress(lpMemTarget, nBytes));
//	ASSERT(AfxIsValidAddress(lpMemSource, nBytes, FALSE));

	return (BYTE*)memcpy(lpMemTarget, lpMemSource, nBytes);
}
#pragma function(memcpy)

void CAnsiMemFile::Free(BYTE* lpMem)
{
	ASSERT(lpMem != NULL);

	free(lpMem);
}

ULONGLONG CAnsiMemFile::GetPosition() const
{
//	ASSERT_VALID(this);
	return m_nPosition;
}

void CAnsiMemFile::GrowFile(SIZE_T dwNewLen)
{
//	ASSERT_VALID(this);

	if (dwNewLen > m_nBufferSize)
	{
		// grow the buffer
		SIZE_T dwNewBufferSize = m_nBufferSize;

		// watch out for buffers which cannot be grown!
		ASSERT(m_nGrowBytes != 0);
//		if (m_nGrowBytes == 0)
//			AfxThrowMemoryException();

		// determine new buffer size
		while (dwNewBufferSize < dwNewLen)
			dwNewBufferSize += m_nGrowBytes;

		// allocate new buffer
		BYTE* lpNew;
		if (m_lpBuffer == NULL)
			lpNew = Alloc(dwNewBufferSize);
		else
			lpNew = Realloc(m_lpBuffer, dwNewBufferSize);

//		if (lpNew == NULL)
//			AfxThrowMemoryException();

		m_lpBuffer = lpNew;
		m_nBufferSize = dwNewBufferSize;
	}
//	ASSERT_VALID(this);
}

BYTE* CAnsiMemFile::GetBuffer(void)
{
	ASSERT( m_lpBuffer != NULL );

#ifndef _DEBUG

	if( m_lpBuffer == NULL )
	{
		GrowFile( 1024 );
	}

#endif

    return m_lpBuffer;
}

ULONGLONG CAnsiMemFile::GetLength() const
{
//	ASSERT_VALID(this);

	return m_nFileSize;
}

void CAnsiMemFile::SetLength(ULONGLONG dwNewLen)
{
//	ASSERT_VALID(this);

#ifdef WIN32
//	if (dwNewLen > ULONG_MAX)
//		AfxThrowMemoryException();
#endif  // WIN32
	if (dwNewLen > m_nBufferSize)
		GrowFile((SIZE_T)dwNewLen);

	if (dwNewLen < m_nPosition)
		m_nPosition = (SIZE_T)dwNewLen;

	m_nFileSize = (SIZE_T)dwNewLen;
//	ASSERT_VALID(this);
}

UINT CAnsiMemFile::Read(void* lpBuf, UINT nCount)
{
//	ASSERT_VALID(this);

	if (nCount == 0)
		return 0;

	ASSERT(lpBuf != NULL);


//	ASSERT(AfxIsValidAddress(lpBuf, nCount));

	if (m_nPosition > m_nFileSize)
		return 0;

	UINT nRead;
	if (m_nPosition + nCount > m_nFileSize)
		nRead = (UINT)(m_nFileSize - m_nPosition);
	else
		nRead = nCount;

	Memcpy((BYTE*)lpBuf, (BYTE*)m_lpBuffer + m_nPosition, nRead);
	m_nPosition += nRead;

//	ASSERT_VALID(this);

	return nRead;
}

void CAnsiMemFile::Write(const void* lpBuf, UINT nCount)
{
//	ASSERT_VALID(this);

	if (nCount == 0)
		return;

	ASSERT(lpBuf != NULL);
//	ASSERT(AfxIsValidAddress(lpBuf, nCount, FALSE));


	if (m_nPosition + nCount > m_nBufferSize)
		GrowFile(m_nPosition + nCount);

	ASSERT(m_nPosition + nCount <= m_nBufferSize);

	Memcpy((BYTE*)m_lpBuffer + m_nPosition, (BYTE*)lpBuf, nCount);

	m_nPosition += nCount;

	if (m_nPosition > m_nFileSize)
		m_nFileSize = m_nPosition;

//	ASSERT_VALID(this);
}

ULONGLONG CAnsiMemFile::Seek(LONGLONG lOff, UINT nFrom)
{
//	ASSERT_VALID(this);
	ASSERT(nFrom == begin || nFrom == end || nFrom == current);

	LONGLONG lNewPos = m_nPosition;

	if (nFrom == begin)
		lNewPos = lOff;
	else if (nFrom == current)
		lNewPos += lOff;
	else if (nFrom == end) {
		if (lOff > 0) 
		{
//			AfxThrowFileException(CFileException::badSeek);// offsets must be negative when seeking from the end
		}
		lNewPos = m_nFileSize + lOff;	
	} else
		return m_nPosition;

//	if (lNewPos < 0)
//		AfxThrowFileException(CFileException::badSeek);
	if (static_cast<DWORD>(lNewPos) > m_nFileSize)
		GrowFile((SIZE_T)lNewPos);

	m_nPosition = (SIZE_T)lNewPos;

//	ASSERT_VALID(this);
	return m_nPosition;
}

ULONGLONG CAnsiMemFile::SeekToBegin()
{
	return Seek( 0, begin );
}
ULONGLONG CAnsiMemFile::SeekToEnd() 
{
    return Seek( 0, end );
}

void CAnsiMemFile::Flush()
{
//	ASSERT_VALID(this);
}

void CAnsiMemFile::Close()
{
	//ASSERT((m_lpBuffer == NULL && m_nBufferSize == 0) || !m_bAutoDelete);
	// ASSERT((m_lpBuffer == NULL && m_nBufferSize == 0));

	ASSERT(m_nFileSize <= m_nBufferSize);

	m_nGrowBytes = 0;
	m_nPosition = 0;
	m_nBufferSize = 0;
	m_nFileSize = 0;
	if (m_lpBuffer && m_bAutoDelete)
		Free(m_lpBuffer);
	m_lpBuffer = NULL;
}

void CAnsiMemFile::Abort()
{
//	ASSERT_VALID(this);
	Close();
}



